package com.suray.wcs.service.test.action;

import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.path.enums.NodeType;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.service.enums.TaskStatus;
import com.suray.wcs.service.enums.TaskType;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.system.entity.TaskDB;
import com.suray.wcs.service.system.service.impl.NodeDBServiceImpl;
import com.suray.wcs.service.system.service.impl.TaskDBServiceImpl;
import com.suray.wcs.service.test.base.BaseThread;
import com.suray.wcs.service.test.type.TestTaskProcess;
import com.suray.wcs.service.util.WcsUtil;

import java.util.*;

/**
 * 任务循环测试
 * 空载、移库
 */
public class TaskCycleAction extends BaseThread {
    /**
     * 所有小车循环任务
     */
    private static Map<Rgv, TaskCycleAction> tasks = new HashMap<>();

    /**
     * 执行任务的小车
     */
    private Rgv rgv;

    /**
     * 任务类型
     */
    private TaskType taskType;

    /**
     * 节点1
     */
    private Node firstNode;

    /**
     * 节点2
     */
    private Node secondNode;

    /**
     * 执行进度
     */
    private TestTaskProcess process;

    /**
     * 当前执行的任务
     */
    private TaskDB task;

    private List<Node> nodes;

    private TaskDBServiceImpl taskDBService = SpringContextHolder.getBean(TaskDBServiceImpl.class);
    private NodeDBServiceImpl nodeDBService = SpringContextHolder.getBean(NodeDBServiceImpl.class);

    public TaskCycleAction(Rgv rgv, TaskType taskType, Node node) {
        super("任务循环测试", 1000);

        nodes = analyzeNodes(taskType);

        this.rgv = rgv;
        this.taskType = taskType;

        process = TestTaskProcess.INIT;

        firstNode = new Node(rgv.getCurLocation());
        secondNode = new Node(node);

        tasks.put(rgv, this);
    }

    @Override
    protected void process() {
        switch (process) {
            case INIT:
                process = TestTaskProcess.FIRST_TASK;
                break;
            case FIRST_TASK:
//                secondNode = findNode(rgv.getCurLocation());
                if (taskType == TaskType.MOVE_LOADED) {
                    task = WcsUtil.generalTask(null, secondNode, rgv, taskType, taskDBService, this.getClass());
                } else {
                    task = WcsUtil.generalTask(firstNode, secondNode, rgv, taskType, taskDBService, this.getClass());
                }
                process = TestTaskProcess.WAIT_FIRST_TASK_END;
                break;
            case WAIT_FIRST_TASK_END:
                task = taskDBService.getById(task);
                if (task.getTaskStatus() == TaskStatus.FINISH) {
                    LoggerUtil.info(rgv.getRgvName() + "任务完成：" + task, this.getClass());
                    process = TestTaskProcess.SECOND_TASK;
                    task = null;
                }
                break;
            case SECOND_TASK:
//                firstNode = findNode(rgv.getCurLocation());
                if (taskType == TaskType.MOVE_LOADED) {
                    task = WcsUtil.generalTask(null, firstNode, rgv, taskType, taskDBService, this.getClass());
                } else {
                    task = WcsUtil.generalTask(secondNode, firstNode, rgv, taskType, taskDBService, this.getClass());
                }
                process = TestTaskProcess.WAIT_SECOND_TASK_END;
                break;
            case WAIT_SECOND_TASK_END:
                task = taskDBService.getById(task);
                if (task.getTaskStatus() == TaskStatus.FINISH) {
                    LoggerUtil.info(rgv.getRgvName() + "任务完成：" + task, this.getClass());
                    process = TestTaskProcess.FIRST_TASK;
                    task = null;
                }
                break;
            case END:
            default:
                throw new RuntimeException("状态错误：" + toString());
        }
    }

    private List<Node> analyzeNodes(TaskType taskType) {
        List<Node> nodes = new ArrayList<>();
        List<Node> nodeList = nodeDBService.getNodeList();
        nodeList.forEach(node -> {
            if (taskType == TaskType.TRANSFER) {
                if (node.getNodeType() == NodeType.P
                    /*|| node.getNodeType() == NodeType.R*/) {
                    nodes.add(node);
                }
            } else {
                if (node.getNodeType() == NodeType.P
                        || node.getNodeType() == NodeType.R) {
                    nodes.add(node);
                }
            }
        });

        return nodes;
    }

    private Node findNode(Node curLocation) {
        Random random = new Random();
        int index = random.nextInt(nodes.size());

        return nodes.get(index);
    }

    /**
     * 小车当前是否有循环动作
     * @param rgv
     * @return
     */
    public static boolean isRgvHasTask(Rgv rgv) {
        if (tasks.get(rgv) != null) {
            return true;
        }

        return false;
    }

    /**
     * 分析小车，如果已经有任务则删除任务，否则添加任务
     * @param rgv
     * @param taskType
     */
    public synchronized static void analyzeTask(Rgv rgv, TaskType taskType, Node node) {
        if (isRgvHasTask(rgv)) {
            TaskCycleAction task = tasks.get(rgv);
            task.endThread();
            tasks.remove(rgv);
            setRgvTaskInfo(rgv, taskType, false);
            return;
        }

        new TaskCycleAction(rgv, taskType, node).start();
        setRgvTaskInfo(rgv, taskType, true);
    }

    private static void setRgvTaskInfo(Rgv rgv, TaskType taskType, boolean taskStatus) {
        switch (taskType) {
            case MOVE_LOADED:
                rgv.setLoadedLoop(taskStatus);
                break;
            case MOVE_UNLOADED:
                rgv.setUnLoadedLoop(taskStatus);
                break;
            case TRANSFER:
                rgv.setTransferLoop(taskStatus);
                break;
            default:
                break;
        }
    }

    @Override
    public String toString() {
        return "TaskCycleAction{" +
                "rgv=" + rgv +
                ", process=" + process +
                '}';
    }
}
